package com.weirdor.elasticsearch.kit;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.weirdor.elasticsearch.exception.ElasticeException;
import com.weirdor.elasticsearch.utils.ObjectUtils;
import com.weirdor.elasticsearch.utils.StringUtils;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.reindex.*;
import org.elasticsearch.script.Script;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by weirdor on 2017/12/18.
 * 文件描述:Elasticsearch操作工具类
 */
public enum ElasticSearchKit {

    /*
     *枚举实现单例模式
     */
    INSTANCE;
    private static TransportClient client;

    private static Logger logger = LoggerFactory.getLogger(ElasticSearchKit.class.getName());

    public static TransportClient getClient() {
        return client;
    }


    public static void init(TransportClient client) {
        ElasticSearchKit.client = client;
    }


    public Map<String, Object> toMap(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            //或得bean类
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            //获得所有的属性描述
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                /*过滤class属性  */
                if (!key.equals("class")) {
                    //*得到property对应的getter方法*/
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);
                    map.put(key, value);
                }
            }
        } catch (Exception e) {
            ElasticSearchKit.INSTANCE.error("ElasticSearchKit.class", "toMap is error " + e.getMessage());
        }
        return map;
    }

    protected void error(String funName, String text) {
        logger.error("ElasticSearchKit tips: (づ￣ 3￣)づ " + funName + " is error ! " + text);
    }

    /**
     * 保存Map单条数据保存到ES
     *
     * @param indexName  索引名称
     * @param typeName   索引类型
     * @param id         对应数据ID
     * @param jsonObject 数据
     */
    public static String insert(String indexName, String typeName, String id, JSONObject jsonObject) {
        if (jsonObject == null) {
            return null;
        }
        BulkRequestBuilder bulkRequest = client.prepareBulk();
        Object idValue = jsonObject.get(id);
        if (ObjectUtils.isBlank(idValue)) {
            idValue = id;
        }
        // 不指定索引id,索引id自动生成
        if (ObjectUtils.isBlank(id)) {
            IndexRequestBuilder lrb = client.prepareIndex(indexName, typeName).setSource(jsonObject);
            bulkRequest.add(lrb);
        }
        // 根据指定索引id生成索引
        else {
            IndexRequestBuilder lrb = client.prepareIndex(indexName, typeName, idValue.toString()).setSource(jsonObject);
            bulkRequest.add(lrb);
        }
        return bulkRequest.get().buildFailureMessage();
    }



    public void setDebug(boolean debug) {
        ch.qos.logback.classic.Level level;
        if (debug) {
            level = ch.qos.logback.classic.Level.DEBUG;
        } else {
            level = ch.qos.logback.classic.Level.WARN;
        }
        ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
        root.setLevel(level);
    }

    /*由于fastjson转换空对象时就会直接抛出异常,而在实际查询中查不到东西是很正常的
     * ,所以为了避免会有空异常,特别做了异常处理*/

    private JSONObject parseObject(String json) {
        try {
            if (json != null && !json.isEmpty()) {
                return JSON.parseObject(json);
            }
            return new JSONObject();
        } catch (NullPointerException e) {
            error("parseObject", json);
            return new JSONObject();
        }


    }

    private JSONObject toJSON(Object obj) {
        try {
            return (JSONObject) JSON.toJSON(obj);
        } catch (NullPointerException e) {
            error("toJSON", obj.getClass().getName());
            return new JSONObject();
        }
    }

    public String validation(Object obj) {

        StringBuffer buffer = new StringBuffer(64);//用于存储验证后的错误信息

        Validator validator = Validation.buildDefaultValidatorFactory()
                .getValidator();

        Set<ConstraintViolation<Object>> constraintViolations = validator
                .validate(obj);//验证某个对象,其实也可以只验证其中的某一个属性的

        Iterator iter = constraintViolations.iterator();
        while (iter.hasNext()) {
            ConstraintViolation c = (ConstraintViolation) iter.next();
            buffer.append(c.getMessage());
        }

        return buffer.toString();
    }

    //校验单个属性
    public String validation(Object obj, String[] keys) {

        StringBuffer buffer = new StringBuffer(64);//用于存储验证后的错误信息

        Validator validator = Validation.buildDefaultValidatorFactory()
                .getValidator();

        Set<ConstraintViolation<Object>> constraintViolations = new HashSet<ConstraintViolation<Object>>();

        for (String key : keys) {
            Iterator<ConstraintViolation<Object>> it = validator.validateProperty(obj, key).iterator();
            if (it.hasNext()) {
                constraintViolations.add(it.next());
            }

        }


        Iterator iter = constraintViolations.iterator();
        while (iter.hasNext()) {
            ConstraintViolation c = (ConstraintViolation) iter.next();
            buffer.append(c.getMessage());
        }

        return buffer.toString();
    }

    public static String update(String indexName, String typeName, String id, JSONObject jsonObject) {
        if (StringUtils.isEmpty(id)) {
            throw new ElasticeException("id不能为空");
        }
        try {
            UpdateRequest updateRequest = new UpdateRequest(indexName, typeName, id)
                    .doc(jsonObject);
            UpdateResponse updateResponse = client.update(updateRequest).get();
            logger.debug("update idnex version is:" + updateResponse.getVersion());
            return updateResponse.getId();
        } catch (Exception e) {
            logger.debug("The update mechanism is empty");
            throw new ElasticeException("update data failed.", e);
        }
    }

    public static String delete(String indexName, String typeName, String id) {
        if (StringUtils.isEmpty(id)) {
            throw new ElasticeException("id不能为空");
        }
        try {
            DeleteResponse deleteResponse = client.prepareDelete(indexName, typeName, id).get();
            return  deleteResponse.getId();
        } catch (Exception e) {
            logger.debug("The delete id is empty");
            throw new ElasticeException("delete data failed.", e);
        }

    }

    public static String delete(String indexName, String typeName,List<QueryBuilder> queryBuilderList) {
        try {
            DeleteByQueryRequestBuilder builder =DeleteByQueryAction.INSTANCE.newRequestBuilder(client).source(indexName,typeName);
            queryBuilderList.forEach(k->{
                builder.filter(k);
            });
            BulkByScrollResponse response = builder.get();
            long deleted = response.getDeleted(); //删除文档的数量
            return StringUtils.toString(deleted);
        } catch (Exception e) {
            logger.debug("The delete id is empty");
            throw new ElasticeException("delete data failed.", e);
        }

    }

    public static String update(String indexName, String typeName, String id,String script) {
        if (StringUtils.isEmpty(script)){
            throw new ElasticeException("script不能为空");
        }
        if (StringUtils.isEmpty(id)){
            throw new ElasticeException("id不能为空");
        }
        UpdateRequest updateRequest = new UpdateRequest(indexName, typeName, id)
                .script(new Script(script));
      UpdateResponse updateResponse=  client.update(updateRequest).actionGet();
      return  updateResponse.getId();
    }
}
